﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
using System.Net.NetworkInformation;
using System.Net;
using NativeWifi;
using System.Runtime.InteropServices;
using System.Threading;

namespace Client {
	public partial class Form1 : Form {
		delegate void BeginInvokeDelegate();

		public Form1() : this("", 0, "", false, true) {

		}

		public Form1(String host, Decimal port, String iface, Boolean connect, Boolean autoreconnect) {
			InitializeComponent();

			Logger.setTextBox(log);

			this.HandleCreated += (Object o, EventArgs e) => {

				serverConnectionWifiInterfaceRefresh_Click(serverConnectionWifiInterfaceRefresh, EventArgs.Empty);

				if (null == host || host.Length <= 0) {
					host = "localhost";
				}

				if (65535 < port || 1024 > port) {
					port = 8000;
				}

				serverConnectionHost.Text = host;
				serverConnectionPort.Value = port;
				serverConnectionAutoreconnect.Checked = autoreconnect;

				if (null != iface && iface.Length > 0) {
					foreach (NetworkInterface item in serverConnectionWifiInterface.Items) {
						if (item.Name.Equals(iface)) {
							serverConnectionWifiInterface.SelectedItem = item;
							break;
						}
					}
				}

				if (connect) {
					serverConnectionConnect.Checked = true;
				}
			};
		}

		private void serverConnectionConnect_CheckedChanged(object sender, EventArgs e) {
			if (!serverConnectionConnect.Enabled) {
				return;
			}

			keepAliveTimer.Enabled = false;
			BackgroundWorker backgroundWorker = new BackgroundWorker();

			if (serverConnectionWifiInterface.SelectedIndex < 0) {
				serverConnectionConnect.Enabled = false;
				MessageBox.Show("Please select wireless interface", "Validation", MessageBoxButtons.OK, MessageBoxIcon.Stop);
				serverConnectionConnect.Checked = false;
				serverConnectionConnect.Enabled = true;
				return;
			}

			Wifi.Instance.Interface = (NetworkInterface) serverConnectionWifiInterface.SelectedItem;

			Boolean connectRequest = serverConnectionConnect.Checked;
			serverConnectionPort.Enabled = false;
			serverConnectionConnect.Enabled = false;
			serverConnectionWifiInterface.Enabled = false;
			serverConnectionHost.Enabled = false;
			serverConnectionWifiInterfaceRefresh.Enabled = false;

			if (serverConnectionConnect.Checked) {
				serverConnectionConnect.Text = "Connecting...";
			} else {
				serverConnectionConnect.Text = "Disconnecting...";
			}

			backgroundWorker.DoWork += (o, ev) => {
				if (!serverConnectionConnect.Checked) {
					Logger.Info("Disconnecting from server...");

					ServiceClient.Instance.Disconnect();
				} else {
					Logger.Info("Connecting to server...");

					ServiceClient.Instance.SetPort(serverConnectionPort.Value);
					ServiceClient.Instance.SetHost(serverConnectionHost.Text);
					ServiceClient.Instance.Connect();
				}
			};
			backgroundWorker.RunWorkerCompleted += (o, ev) => {
				if (serverConnectionAutoreconnect.Checked && connectRequest && !ServiceClient.Instance.IsConnected()) {
					Logger.Info("Not connected. Reconnecting in 5s...");

					System.Timers.Timer timer = new System.Timers.Timer();
					timer.Interval = 5000;
					timer.AutoReset = false;

					timer.Elapsed += (obj, ea) => {
						serverConnectionConnect.BeginInvoke(new BeginInvokeDelegate(() => {
							Logger.Info("Reconnecting now!");
							serverConnectionConnect.Checked = false;
							serverConnectionConnect.Enabled = true;
							serverConnectionConnect.Checked = true;
						}));
					};
					timer.Start();
				} else {

					if (ServiceClient.Instance.IsConnected()) {
						serverConnectionConnect.Checked = true;

						serverConnectionConnect.Text = "Disconnect";
						Logger.Info("Client has connected...");

						Wifi.Instance.Interface = (NetworkInterface) serverConnectionWifiInterface.SelectedItem;
					} else {
						serverConnectionConnect.Checked = false;

						serverConnectionPort.Enabled = true;
						serverConnectionWifiInterface.Enabled = true;
						serverConnectionHost.Enabled = true;
						serverConnectionWifiInterfaceRefresh.Enabled = true;
						serverConnectionConnect.Text = "Connect";
						Logger.Info("Client has disconnected...");
					}
					serverConnectionConnect.Enabled = true;

					keepAliveTimer.Enabled = true;
				}
			};
			backgroundWorker.RunWorkerAsync();
		}

		private void serverConnectionWifiInterfaceRefresh_Click(object sender, EventArgs e) {
			Logger.Debug("Scanning for wireless network interfaces...");
			serverConnectionWifiInterface.Items.Clear();

			WlanClient client = new WlanClient();
			foreach (WlanClient.WlanInterface iface in client.Interfaces) {
				NetworkInterface netif = iface.NetworkInterface;

				if (null != netif.GetIPProperties().UnicastAddresses && netif.GetIPProperties().UnicastAddresses.Count > 0) {
					foreach (UnicastIPAddressInformation unicast in netif.GetIPProperties().UnicastAddresses) {
						if (unicast.Address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork) {
							continue;
						}

						String mask;
						if (null == unicast.IPv4Mask) {
							mask = "-";
						} else {
							mask = unicast.IPv4Mask.ToString();
						}
						Logger.Info(netif.NetworkInterfaceType + " (" + netif.Name + "): " + unicast.Address + "/" + mask + " (" + (Math.Round(netif.Speed / 1000000.0, 2)) + "Mbps)");
					}
				} else {
					Logger.Info(netif.NetworkInterfaceType + " (" + netif.Name + "): interface without configured address");
				}
				serverConnectionWifiInterface.Items.Add(netif);
			}

			if (serverConnectionWifiInterface.Items.Count > 0) {
				serverConnectionWifiInterface.SelectedIndex = 0;
			}
		}

		private void keepAliveTimer_Tick(object sender, EventArgs e) {
			BackgroundWorker backgroundWorker = new BackgroundWorker();

			// interval od zakończonego połączenia...
			keepAliveTimer.Enabled = false;

			backgroundWorker.DoWork += (o, ea) => {
				// jeśli jest połączenie
				if (ServiceClient.Instance.IsConnected()) {
					// sprawdź je
					if (!ServiceClient.Instance.TestConnection()) {
						// jeśli jest wadliwe, rozłącz
						Logger.Warning("Connection lost, disconnecting...");
						ServiceClient.Instance.Disconnect();
					}
				}
			};

			backgroundWorker.RunWorkerCompleted += (o, ea) => {
				// włącz timer, żeby sprawdzał połączenie
				keepAliveTimer.Enabled = true;
				if (!ServiceClient.Instance.IsConnected() && serverConnectionConnect.Checked) {
					Logger.Info("Reconnecting 'cause connection lost...");
					serverConnectionConnect_CheckedChanged(sender, EventArgs.Empty);
				}
			};

			backgroundWorker.RunWorkerAsync();
		}

		private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
			serverConnectionConnect.Checked = false;
			Wifi.Instance.Disconnect();
		}
	}
}
